package org.hit.burkun.umls.relation;

import java.util.HashMap;
import java.util.HashSet;

import javax.annotation.Nonnull;

import org.hit.burkun.entities.Entity;

public class UniformRelation {
	public enum TYPE {
		DO_IS_A("do_is_a"), DO_XREF_OMIM_GENE("do_xref_omim_gene"),

		GO_IS_A("go_is_a"), GO_HAPPENS_DURING("go_happends_during"), GO_HAS_PART(
				"go_has_part"), GO_NEGATIVELY_REGULATES(
				"go_negatively_regulates"), GO_OCCURS_IN("go_occurs_in"), GO_POSITIVELY_REGULTATES(
				"go_positively_regulates"), GO_REGULTATES("go_regulates"), GO_PART_OF(
				"go_part_of"),

		OMIM_GENE("omim_gene"),

		HP_ANNOTATION_GENE_IEA("hp_annotation_gene_IEA"), //inferred from electronic annotation
		HP_ANNOTATION_GENE_ICE("hp_annotation_gene_ICE"), //published clinical study PCS
		HP_ANNOTATION_GENE_PCS("hp_annotation_gene_PCS"), //"ICE" can be used for annotations based on individual clinical experience.
		HP_ANNOTATION_GENE_TAS("hp_annotation_gene_TAS"), //annotations retrieved by text-mining (inferred by text-mining)  ITM
		//traceable author statement
		HP_IS_A("hp_is_a"), 
		HP_FILE_GENE("hp_file_gene"), 
		// 官网提供的hp到gene的映射，没有置信度
	    //http://geneontology.org/page/guide-go-evidence-codes
		/*
		 * 	Experimental Evidence codes 
		 * 		Inferred from Experiment (EXP)
				Inferred from Direct Assay (IDA)
				Inferred from Physical Interaction (IPI)
				Inferred from Mutant Phenotype (IMP)
				Inferred from Genetic Interaction (IGI)
				Inferred from Expression Pattern (IEP)
		 * EXP IDA IPI IMP IGI IEP
		 * */
		GO_ANNOTATION_GENE_IEA("go_annotation_gene_IEA"), GO_ANNOTATION_GENE_TAS(
				"go_annotation_gene_TAS"), GO_ANNOTATION_GENE_IDA(
				"go_annotation_gene_IDA"), GO_ANNOTATION_GENE_IPI(
				"go_annotation_gene_IPI"), GO_ANNOTATION_GENE_IBA(
				"go_annotation_gene_IBA"), GO_ANNOTATION_GENE_ISS(
				"go_annotation_gene_ISS"), GO_ANNOTATION_GENE_IMP(
				"go_annotation_gene_IMP"), GO_ANNOTATION_GENE_NAS(
				"go_annotation_gene_NAS"), GO_ANNOTATION_GENE_ND(
				"go_annotation_gene_ND"), GO_ANNOTATION_GENE_IC(
				"go_annotation_gene_IC"), GO_ANNOTATION_GENE_IEP(
				"go_annotation_gene_IEP"), GO_ANNOTATION_GENE_IGI(
				"go_annotation_gene_IGI"), GO_ANNOTATION_GENE_EXP(
				"go_annotation_gene_EXP"), GO_ANNOTATION_GENE_IKR(
				"go_annotation_gene_IKR"),
				GO_ANNOTATION_GENE_IRD("go_annotation_gene_IRD"),
				

		STRING_GENE("string_gene"), DISEASE_CLINVAR_GENE("disease_clinvar_gene"), DISEASE_CTD_GENE_CURATED(
				"disease_ctd_gene_curated"), DISEASE_CTD_GENE_INFERED(
				"disease_ctd_gene_infered"),

		DO_SIDD_MFS_MESH_GENE("do_sidd_mesh_gene_MFS"), DO_SIDD_MFI_MESH_GENE(
				"do_sidd_mesh_gene_MFI"), DO_SIDD_MFR_MESH_GENE(
				"do_sidd_mesh_gene_MFR"),
		DO_SIDD_MFS_OMIM_GENE("do_sidd_omim_gene_MFS"), DO_SIDD_MFI_OMIM_GENE(
				"do_sidd_omim_gene_MFI"), DO_SIDD_MFR_OMIM_GENE(
				"do_sidd_omim_gene_MFR");
		

		@Nonnull
		private final String tag;

		TYPE(@Nonnull String tag) {
			this.tag = tag;
		}

		/** @return tag */
		@Nonnull
		public String getTag() {
			return tag;
		}

		@Override
		public String toString() {
			return tag;
		}

		public static TYPE getTypeByTag(String tag) {
			TYPE type = null;
			if (tag.equals(DO_IS_A.getTag()))
				type = DO_IS_A;
			else if (tag.equals(DO_SIDD_MFI_MESH_GENE.getTag()))
				type = DO_SIDD_MFI_MESH_GENE;
			else if (tag.equals(DO_SIDD_MFS_MESH_GENE.getTag()))
				type = DO_SIDD_MFS_MESH_GENE;
			else if (tag.equals(DO_SIDD_MFR_MESH_GENE.getTag()))
				type =  DO_SIDD_MFR_MESH_GENE;
			else if (tag.equals(DO_SIDD_MFI_OMIM_GENE.getTag()))
				type = DO_SIDD_MFI_OMIM_GENE;
			else if (tag.equals(DO_SIDD_MFS_OMIM_GENE.getTag()))
				type =  DO_SIDD_MFS_OMIM_GENE;
			else if (tag.equals(DO_SIDD_MFR_OMIM_GENE.getTag()))
				type = DO_SIDD_MFR_OMIM_GENE;
			else if (tag.equals(GO_IS_A.getTag()))
				type = GO_IS_A;
			else if (tag.equals(HP_IS_A.getTag()))
				type = HP_IS_A;
			else if (tag.equals(GO_PART_OF.getTag()))
				type = GO_PART_OF;
			else if (tag.equals(OMIM_GENE.getTag()))
				type = OMIM_GENE;
			else if (tag.equals(HP_ANNOTATION_GENE_ICE.getTag()))
				type = HP_ANNOTATION_GENE_ICE;
			else if (tag.equals(HP_ANNOTATION_GENE_IEA.getTag()))
				type = HP_ANNOTATION_GENE_IEA;
			else if (tag.equals(HP_ANNOTATION_GENE_PCS.getTag()))
				type = HP_ANNOTATION_GENE_PCS;
			else if (tag.equals(HP_ANNOTATION_GENE_TAS.getTag()))
				type = HP_ANNOTATION_GENE_TAS;
			else if (tag.equals(DO_XREF_OMIM_GENE.getTag()))
				type = DO_XREF_OMIM_GENE;
			else if (tag.equals(GO_ANNOTATION_GENE_EXP.getTag()))
				type = GO_ANNOTATION_GENE_EXP;
			else if (tag.equals(GO_ANNOTATION_GENE_TAS.getTag()))
				type = GO_ANNOTATION_GENE_TAS;
			else if (tag.equals(GO_ANNOTATION_GENE_IEA.getTag()))
				type = GO_ANNOTATION_GENE_IEA;
			else if (tag.equals(GO_ANNOTATION_GENE_IDA.getTag()))
				type = GO_ANNOTATION_GENE_IDA;
			else if (tag.equals(GO_ANNOTATION_GENE_IPI.getTag()))
				type = GO_ANNOTATION_GENE_IPI;
			else if (tag.equals(GO_ANNOTATION_GENE_IBA.getTag()))
				type = GO_ANNOTATION_GENE_IBA;
			else if (tag.equals(GO_ANNOTATION_GENE_ISS.getTag()))
				type = GO_ANNOTATION_GENE_ISS;
			else if (tag.equals(GO_ANNOTATION_GENE_NAS.getTag()))
				type = GO_ANNOTATION_GENE_NAS;
			else if (tag.equals(GO_ANNOTATION_GENE_IMP.getTag()))
				type = GO_ANNOTATION_GENE_IMP;
			else if (tag.equals(GO_ANNOTATION_GENE_ND.getTag()))
				type = GO_ANNOTATION_GENE_ND;
			else if (tag.equals(GO_ANNOTATION_GENE_IC.getTag()))
				type = GO_ANNOTATION_GENE_IC;
			else if (tag.equals(GO_ANNOTATION_GENE_IEP.getTag()))
				type = GO_ANNOTATION_GENE_IEP;
			else if (tag.equals(GO_ANNOTATION_GENE_IGI.getTag()))
				type = GO_ANNOTATION_GENE_IGI;
			else if (tag.equals(GO_ANNOTATION_GENE_IKR.getTag()))
				type = GO_ANNOTATION_GENE_IKR;
			else if (tag.equals(GO_ANNOTATION_GENE_IRD.getTag()))
				type = GO_ANNOTATION_GENE_IRD;
			else if (tag.equals(STRING_GENE.getTag()))
				type = STRING_GENE;
			else if (tag.equals(DISEASE_CLINVAR_GENE.getTag()))
				type = DISEASE_CLINVAR_GENE;
			else if (tag.equals(DISEASE_CTD_GENE_CURATED.getTag()))
				type = DISEASE_CTD_GENE_CURATED;
			else if (tag.equals(DISEASE_CTD_GENE_INFERED.getTag()))
				type = DISEASE_CTD_GENE_INFERED;
			else if (tag.equals(GO_POSITIVELY_REGULTATES.getTag())) {
				type =  GO_POSITIVELY_REGULTATES;
			} else if (tag.equals(GO_HAS_PART.getTag())) {
				type =  GO_HAS_PART;
			} else if (tag.equals(GO_NEGATIVELY_REGULATES.getTag())) {
				type =  GO_NEGATIVELY_REGULATES;
			} else if (tag.equals(GO_OCCURS_IN.getTag())) {
				type =  GO_OCCURS_IN;
			} else if (tag.equals(GO_REGULTATES.getTag())) {
				type =  GO_REGULTATES;
			} else if (tag.equals(GO_HAPPENS_DURING.getTag())) {
				type =  GO_HAPPENS_DURING;
			}
			if(type == null){
				return null;
			}
			if(filterSet.contains(type)){
				return null;
			}
			return type;
		}
	}
	//do_is_a, hp_is_a, go_*, do_gene, go_gene,  hp_gene, gene_gene
	public static double[] weights =new double[] {1, 1, 1, 1, 1, 1, 1};
	//获取全局类型的权值
	public static double getGlobalWeight(HashSet<String> types){
		for(String str : types){
			double weight = getGlobalWeight(UniformRelation.TYPE.getTypeByTag(str));
			if(weight != 1);{
				return weight;
			}
		}
		return 1;
	}
	public static double getGlobalWeight(TYPE type){
		if(type == null) return 1;
		switch (type) {
		case DO_IS_A:
			return weights[0];
		case HP_IS_A:
			return weights[1];
		case GO_IS_A:
		case GO_PART_OF:
		case GO_REGULTATES:
		case GO_HAPPENS_DURING:
		case GO_NEGATIVELY_REGULATES:
		case GO_POSITIVELY_REGULTATES:
		case GO_OCCURS_IN:
			return weights[2];
		case DO_SIDD_MFI_MESH_GENE:
		case DO_SIDD_MFI_OMIM_GENE:
		case DO_SIDD_MFS_MESH_GENE:
		case DO_SIDD_MFS_OMIM_GENE:
		case DO_SIDD_MFR_MESH_GENE:
		case DO_SIDD_MFR_OMIM_GENE:
		case DO_XREF_OMIM_GENE:
			return weights[3];
		case GO_ANNOTATION_GENE_EXP:
		case GO_ANNOTATION_GENE_IPI:
		case GO_ANNOTATION_GENE_IDA:
		case GO_ANNOTATION_GENE_IMP:
		case GO_ANNOTATION_GENE_IGI:
		case GO_ANNOTATION_GENE_IEP:
		case GO_ANNOTATION_GENE_IKR:
		case GO_ANNOTATION_GENE_ISS:
		case GO_ANNOTATION_GENE_IBA:
		case GO_ANNOTATION_GENE_IRD:
		case GO_ANNOTATION_GENE_TAS:
		case GO_ANNOTATION_GENE_IC:
		case GO_ANNOTATION_GENE_ND:
		case GO_ANNOTATION_GENE_IEA:
		case GO_ANNOTATION_GENE_NAS:
			return weights[4];
		case HP_ANNOTATION_GENE_ICE:
		case HP_ANNOTATION_GENE_PCS:
		case HP_ANNOTATION_GENE_TAS:
		case HP_ANNOTATION_GENE_IEA:
		case HP_FILE_GENE:
			return weights[5];
		case DISEASE_CTD_GENE_CURATED:
		case DISEASE_CLINVAR_GENE:
			return 1;
		case STRING_GENE:
			return weights[6];
		default:
			return 1;
		}
	}
	//过滤掉ontology不需要的部分
	private static HashSet<TYPE> filterSet = new HashSet<>();
	//考虑到sidd和ctd部分用到了omim，所以这里认为DO_SIDD_MFR_OMIM_GENE， DO_SIDD_MFR_MESH_GENE，DO_XREF_OMIM_GENE是一个东西
	private static HashSet<TYPE> sameEvidence = new HashSet<>();
	//保存的是对应的权值
	private static HashMap<TYPE, Double> scoresMap = new HashMap<TYPE, Double>();
	static {
		//ontology weight
		scoresMap.put(TYPE.DO_IS_A, 1.0);
		scoresMap.put(TYPE.HP_IS_A, 1.0);
		scoresMap.put(TYPE.GO_IS_A, 1.0);
		scoresMap.put(TYPE.GO_PART_OF, 0.8);
		scoresMap.put(TYPE.GO_HAS_PART, 0.6);
		scoresMap.put(TYPE.GO_HAPPENS_DURING, 0.6);
		scoresMap.put(TYPE.GO_NEGATIVELY_REGULATES, 0.6);
		scoresMap.put(TYPE.GO_POSITIVELY_REGULTATES, 0.6);
		scoresMap.put(TYPE.GO_OCCURS_IN, 0.6);
		scoresMap.put(TYPE.GO_REGULTATES, 0.8);
		
		//annotation wight
		scoresMap.put(TYPE.DO_SIDD_MFI_MESH_GENE, 0.6);
		scoresMap.put(TYPE.DO_SIDD_MFI_OMIM_GENE, 0.6);
		scoresMap.put(TYPE.DO_SIDD_MFS_MESH_GENE, 1.0);
		scoresMap.put(TYPE.DO_SIDD_MFS_OMIM_GENE, 1.0);
		scoresMap.put(TYPE.DO_SIDD_MFR_MESH_GENE, 1.0); //一样的
		scoresMap.put(TYPE.DO_SIDD_MFR_OMIM_GENE, 1.0); //一样的
		scoresMap.put(TYPE.DO_XREF_OMIM_GENE, 1.0); //一样的
		//go EXP IDA IPI IMP IGI IEP
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_EXP, 1.0);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IDA, 1.0);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IPI, 1.0);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IMP, 1.0);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IGI, 1.0);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IEP, 1.0);
		// go other computed
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_ISS, 0.6);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IKR, 0.6);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IBA, 0.6);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IRD, 0.6);

		//author statement codes
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_TAS, 0.7);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_NAS, 0.7);
		//curatorial statement
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IC, 0.7);
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_ND, 0.4);
		//electronic annotation
		scoresMap.put(TYPE.GO_ANNOTATION_GENE_IEA, 0.4);
		

		//---hp
		scoresMap.put(TYPE.HP_ANNOTATION_GENE_ICE, 0.8); //ICE" can be used for annotations based on individual clinical experience.
		scoresMap.put(TYPE.HP_ANNOTATION_GENE_PCS, 0.8); //published clinical study PCS
		scoresMap.put(TYPE.HP_ANNOTATION_GENE_TAS, 0.8); //traceable author statement
		scoresMap.put(TYPE.HP_ANNOTATION_GENE_IEA, 0.4);//inferred from electronic annotation
		scoresMap.put(TYPE.HP_FILE_GENE, 0.3);//这个来源太不可靠了
		scoresMap.put(TYPE.DISEASE_CTD_GENE_CURATED, 1.0);
		//--- clinvar DISEASE_CLINVAR_GENE
		scoresMap.put(TYPE.DISEASE_CLINVAR_GENE, 1.0);//clinvar的基因突变信息
		
		//string -gene 本身就有score，这里就用本身的
		scoresMap.put(TYPE.STRING_GENE, 1.0);
		
		//init filter
		filterSet.add(TYPE.GO_HAPPENS_DURING);
		filterSet.add(TYPE.GO_OCCURS_IN);
		filterSet.add(TYPE.GO_HAS_PART);
		filterSet.add(TYPE.GO_NEGATIVELY_REGULATES);
		filterSet.add(TYPE.GO_POSITIVELY_REGULTATES);
		//init same evidence
		sameEvidence.add(TYPE.DO_XREF_OMIM_GENE);
		sameEvidence.add(TYPE.DO_SIDD_MFR_MESH_GENE);
		sameEvidence.add(TYPE.DO_SIDD_MFR_OMIM_GENE);
		sameEvidence.add(TYPE.OMIM_GENE);
	}

	public static double getScoreByType(TYPE type) {
		if (scoresMap.containsKey(type)) {
			return scoresMap.get(type);
		}
		//不存在的同意标记成0.1的概率
		return 0.1;
	}
	//包含吗？
	public static boolean containSame(TYPE type){
		if(sameEvidence.contains(type)){
			return true;
		}
		return false;
	}

	public static Double getScoreByType(String type) {
		TYPE t = TYPE.getTypeByTag(type);
		if (scoresMap.containsKey(t)) {
			return scoresMap.get(t);
		}
		//不存在的同意标记成0.1的概率
		return 0.1;
	}

	private boolean isDirect = false;
	private TYPE type;
	private Entity ent1;
	private Entity ent2;
	// 计算置信度
	private String confidscore;

	public UniformRelation(Entity ent1, Entity ent2, boolean isDirect, TYPE type) {
		this.isDirect = isDirect;
		this.type = type;
		this.ent1 = ent1;
		this.ent2 = ent2;
	}

	@Override
	public String toString() {
		if (this.isDirect) {
			return this.ent1.getDbid() + "->" + ent2.getDbid() + " "
					+ type.getTag();
		}
		return this.ent1.getDbid() + "<->" + ent2.getDbid() + " "
				+ type.getTag();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof UniformRelation) {
			UniformRelation r = (UniformRelation) obj;
			if (r.getEnt1().equals(this.ent1) && r.getEnt2().equals(this.ent2)
					&& this.type == r.getType()) {
				return true;
			}
		}
		return false;
	}

	public boolean isDirect() {
		return isDirect;
	}

	public void setDirect(boolean isDirect) {
		this.isDirect = isDirect;
	}

	public TYPE getType() {
		return type;
	}

	public void setType(TYPE type) {
		this.type = type;
	}

	public Entity getEnt1() {
		return ent1;
	}

	public void setEnt1(Entity ent1) {
		this.ent1 = ent1;
	}

	public Entity getEnt2() {
		return ent2;
	}

	public void setEnt2(Entity ent2) {
		this.ent2 = ent2;
	}

	public String getConfidscore() {
		return confidscore;
	}

	public void setConfidscore(String confidscore) {
		this.confidscore = confidscore;
	}

}
